#ifndef xpack_test_utils_array
#define xpack_test_utils_array
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_utils_array::inc
#include"test/helper.hpp" // 需要放第一
#include"dumb/move.hpp"
#include"interface/ranger.hpp"
#include"interface/seqptr.hpp"
#include"macro/xcstyle.hpp"
#include"macro/xmaybe_unused.hpp"
#include"utils/array.hpp"
#include"utils/memory.hpp"
#include"utils/temp_allocator.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_utils_array{
    using nlrd = inc::helper::nlrd_counter;

    inline uxx g_uxx_value;

    xtest("static") {
        using ary = inc::array<nlrd, 10>;

        // 兼容 ranger/seqptr 接口
        {
            ary test0;

            xmaybe_unused inc::ranger<nlrd> ranger = test0;
            xmaybe_unused inc::seqptr<nlrd> seqptr = test0;
        }

        xassert_nlrd(10, 0, 0, 10);


        // 自动初始化，基础测试
        {
            ary test0{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            xassert_nlrd(10, 0, 0, 0);

            // 测试 foreach 接口
            uxx i = 0;
            test0.foreach([&](nlrd const & item){
                xassert_eq(item.value, i);
                i++;
            });

            test0.foreach([&](uxx i, nlrd & item){
                xassert_eq(item.value, i);
            });

            // 测试索引以及回绕索引
            xassert_eq(test0[0].value, 0u);
            xassert_eq(test0[-1].value, 9u);

            inc::array<nlrd, 1> test1{ 1024 };
            xassert_nlrd(1, 0, 0, 0);
            xassert_eq(test1[0].value, 1024u);
            xassert_eq(test1[-1].value, 1024u);
        }

        xassert_nlrd(0, 0, 0, 11);



        // 右值初始化
        {
            ary test0{ nlrd{} };
            xassert_nlrd(10, 0, 1, 1);
        }

        xassert_nlrd(0, 0, 0, 10);



        // 左值初始化
        {
            nlrd foo;
            ary test0{ foo };
            xassert_nlrd(10, 1, 0, 0);
        }

        xassert_nlrd(0, 0, 0, 11);



        // 左值转右值初始化
        {
            nlrd foo;
            ary test0{ inc::move(foo) };
            xassert_nlrd(10, 0, 1, 0);
        }

        xassert_nlrd(0, 0, 0, 11);


        {
            auto test0 = inc::make_array(nlrd{}, nlrd{});
            xassert_nlrd(2, 0, 2, 2);
        }

        xassert_nlrd(0, 0, 0, 2);


        {
            nlrd foo{};
            xassert_nlrd(1, 0, 0, 0);
            auto test0 = inc::make_array(nlrd{}, foo);
            xassert_nlrd(1/*nlrd{}*/, 1/*foo*/, 1/* nlrd{} */, 1/*nlrd{}*/);
        }

        xassert_nlrd(0, 0, 0, 3/*test0 -> 2  foo -> 1*/);


        {
            auto func = [](ary){};
            func({ nlrd{} });
        }
    };

    xtest("dynamic"){
        using ary = inc::array<nlrd>;

        // 兼容 ranger/seqptr 接口
        {
            ary test0;

            xmaybe_unused inc::ranger<nlrd> ranger = test0;

            xmaybe_unused inc::seqptr<nlrd> seqptr = test0;
        }

        xassert_nlrd(0, 0, 0, 0);


        // 空元素
        auto used_bytes = inc::memory::used_bytes();
        {
            ary test0 = nullptr;
            ary test1;
            xassert_eq(test0, nullptr);
            xassert_eq(test0->length, 0u);
            xassert_eq(test1, nullptr);
            xassert_eq(test1->length, 0u);

            uxx i = 0;
            test0.foreach([&](auto){
                i++;
            });

            test1.foreach([&](auto){
                i++;
            });

            xassert_eq(i, 0u);
        }

        xassert_eq(used_bytes, inc::memory::used_bytes());

        // 一个元素初始化
        used_bytes = inc::memory::used_bytes();
        {
            ary test0{ nlrd{ 1024 } };
            xassert_nlrd(1/* nlrd{} */, 0, 1/* test0 */, 1/* nlrd{} */);

            uxx i = 0;
            test0.foreach([&](nlrd & item){
                xassert_eq(item.value, 1024u);
                i++;
            });

            xassert_eq(i, 1u);
        }
        xassert_nlrd(0, 0, 0, 1/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());


        // 两个元素
        used_bytes = inc::memory::used_bytes();
        {
            ary test0{ nlrd{ 1024 }, nlrd{ 1025 } };
            xassert_nlrd(2/* nlrd{} x2 */, 0, 2/* test0 x2 */, 2/* nlrd{} x2 */);

            uxx i = 0;
            test0.foreach([&](nlrd & item){
                xassert_eq(1024 + i, item.value);
                i++;
            });

            xassert_eq(i, 2u);
        }
        xassert_nlrd(0, 0, 0, 2);
        xassert_eq(used_bytes, inc::memory::used_bytes());

        // 左右值初始化
        used_bytes = inc::memory::used_bytes();
        {
            nlrd foo{ 1234 };
            xassert_nlrd(1/* nlrd{} */, 0, 0, 0);
            ary test0{ nlrd{ 0 }, foo };
            xassert_nlrd(1/* nlrd{} */, 1/* foo */, 1/* test */, 1/* nlrd{} */);
        }
        xassert_nlrd(0, 0, 0, 3);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 申请指定长度的数组
        used_bytes = inc::memory::used_bytes();
        {
            ary test0{ length{16} };
            xassert_nlrd(16/* test0 */, 0, 0, 0);

            for(uxx i = 0; i < test0->length; i++){
                test0[i] = nlrd{i};
            }

            xassert_nlrd(16/* nlrd{} */, 0, 0, 16/* nlrd{} */);
            xassert_alr(0, 16/* = nlrd{i}*/);
        }
        xassert_nlrd(0, 0, 0, 16/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());




        // 申请指定长度的数组并初始化
        used_bytes = inc::memory::used_bytes();
        {
            ary test0(length{2}, [](uxx index, nlrd * mem){
                xnew(mem) nlrd(index);
            });

            xassert_nlrd(2/* test0 */, 0, 0, 0);

            uxx i = 0;
            ary test1(length{2}, [&](nlrd * mem){
                xnew(mem) nlrd(i++);
            });

            xassert_nlrd(2/* test0 */, 0, 0, 0);

            test0.foreach([](uxx index, nlrd & item){
                xassert_eq(index, item.value);
            });

            test1.foreach([](uxx index, nlrd & item){
                xassert_eq(index, item.value);
            });
        }
        xassert_nlrd(0, 0, 0, 4/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());




        // 测试取消析构 is_requires_destruction = false
        used_bytes = inc::memory::used_bytes();
        {
            ary test0{ 1, 2, 3 };
            xassert_nlrd(3/* test0 */, 0, 0, 0);
            test0->is_requires_destruction(false);
        }

        xassert_nlrd(0, 0, 0, 0);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试 hand_over
        used_bytes = inc::memory::used_bytes();
        {
            ary test0;
            {
                ary test1{ 1, 2, 3 };
                xassert_nlrd(3/* test0 */, 0, 0, 0);
                test0 = test1.hand_over();
            }

            xassert_lt(used_bytes, inc::memory::used_bytes());
        }

        xassert_nlrd(0, 0, 0, 3/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());

    };

    xtest("dynamic-constructor"){
        using ary = inc::array<nlrd>;

        // 测试构造函数 array_t(array_t<finalx_t, type_t> && self)
        {
            auto create_ary = [](){
                ary foo;
                return foo;
            };

            ary test0 = create_ary();
            ary test1 = test0.hand_over();
            xassert_eq(test0, nullptr);
            xassert_eq(test1, nullptr);
            xassert_eq(test0->is_requires_free, false);
            xassert_eq(test0->is_requires_destruction, false);
            xassert_eq(test0->has_custom_free, false);
            xassert_eq(test0->addition_bit, 0);
        }

        xassert_nlrd(0, 0, 0, 0);




        // 测试构造函数 array_t(::length capacity, inc::ialloc<void> alloc, initial_invoke_t const & initial, array_custom_free_invoke custom_free = nullptr)
        auto allocator = inc::temp_allocator{};
        auto used_bytes = inc::memory::used_bytes();
        {
            // 注意：
            // 外部分配内存的生命周期应该要比 test0 要长才行，不然就对释放的内存进行析构操作了
            ary test0(length{2}, allocator, [](uxx index, nlrd * mem){
                xnew(mem) nlrd(index);
            });

            xassert_nlrd(2/* test0 */, 0, 0, 0);

            test0.foreach([](uxx index, nlrd & item){
                xassert_eq(index, item.value);
            });


            xassert_eq(test0->is_requires_free, false);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, false);
            xassert_eq(test0->addition_bit, 0);
        }

        allocator.clear();
        xassert_nlrd(0, 0, 0, 2/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试构造函数 array_t(::length capacity, inc::ialloc<void> alloc, initial_invoke_t const & initial, array_custom_free_invoke custom_free)
        used_bytes = inc::memory::used_bytes();
        g_uxx_value = not_exist;
        {
            // 注意：
            // 外部分配内存的生命周期应该要比 test0 要长才行，不然就对释放的内存进行析构操作了
            ary test0(length{2}, allocator, [](uxx index, nlrd * mem){
                xnew(mem) nlrd(index);
            }, xcstyle(inc::array_header_infop info, voidp){
                auto bytes  = info->total_bytes_when_item_is<nlrd>();
                g_uxx_value = bytes;
            });

            xassert_nlrd(2/* test0 */, 0, 0, 0);

            test0.foreach([](uxx index, nlrd & item){
                xassert_eq(index, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, true);
            xassert_eq(test0->addition_bit, 0);
            xassert_eq(g_uxx_value, not_exist);
        }

        xassert_eq(g_uxx_value, allocator->used_bytes);
        allocator.clear();
        xassert_nlrd(0, 0, 0, 2/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试构造函数 array_t(::length capacity, initial_invoke_t const & initial, array_custom_free_invoke custom_free = nullptr)
        used_bytes = inc::memory::used_bytes();
        {
            ary test0(length{4}, [](uxx index, nlrd * mem){
                xnew(mem) nlrd(index);
            }, xcstyle(inc::array_header_infop info, voidp mem){
                auto bytes  = info->total_bytes_when_item_is<nlrd>();
                inc::memory::default_free<void>(mem, bytes);
            });

            xassert_nlrd(4/* test0 */, 0, 0, 0);

            test0.foreach([](uxx index, nlrd & item){
                xassert_eq(index, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, true);
            xassert_eq(test0->addition_bit, 0);
        }

        xassert_nlrd(0, 0, 0, 4/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试构造函数 array_t(::length capacity, inc::ialloc<void> alloc, array_custom_free_invoke custom_free, args_t && ... item_initial_args)
        used_bytes = inc::memory::used_bytes();
        g_uxx_value = not_exist;
        {
            uxx init_value = 123456;
            ary test0(length{1024}, allocator, xcstyle(inc::array_header_infop info, voidp){
                auto bytes = info->total_bytes_when_item_is<nlrd>();
                g_uxx_value = bytes;
            }, init_value);

            xassert_nlrd(1024/* test0 */, 0, 0, 0);

            test0.foreach([&](nlrd & item){
                xassert_eq(init_value, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, true);
            xassert_eq(test0->addition_bit, 0);
            xassert_eq(g_uxx_value, not_exist);
        }

        xassert_eq(g_uxx_value, allocator->used_bytes);
        allocator.clear();
        xassert_nlrd(0, 0, 0, 1024/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());


        // 测试构造函数 array_t(::length capacity, array_custom_free_invoke custom_free, args_t && ... item_initial_args)
        used_bytes = inc::memory::used_bytes();
        {
            uxx init_value = 123456;
            ary test0(length{2048}, xcstyle(inc::array_header_infop info, voidp mem){
                auto bytes = info->total_bytes_when_item_is<nlrd>();
                inc::memory::default_free<void>(mem, bytes);
            }, init_value);

            xassert_nlrd(2048/* test0 */, 0, 0, 0);

            test0.foreach([&](nlrd & item){
                xassert_eq(init_value, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, true);
            xassert_eq(test0->addition_bit, 0);
        }

        xassert_nlrd(0, 0, 0, 2048/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());


        // 测试构造函数 array_t(::length capacity, inc::ialloc<void> alloc, args_t && ... item_initial_args)
        used_bytes = inc::memory::used_bytes();
        {
            uxx init_value = 123456;
            ary test0(length{4096}, allocator, init_value);

            xassert_nlrd(4096/* test0 */, 0, 0, 0);

            test0.foreach([&](nlrd & item){
                xassert_eq(init_value, item.value);
            });

            xassert_eq(test0->is_requires_free, false);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, false);
            xassert_eq(test0->addition_bit, 0);
        }

        allocator.clear();
        xassert_nlrd(0, 0, 0, 4096/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());


        // 测试构造函数 array_t(::length capacity, args_t && ... item_initial_args)
        used_bytes = inc::memory::used_bytes();
        {
            uxx init_value = 123456;
            ary test0(length{8192}, init_value);

            xassert_nlrd(8192/* test0 */, 0, 0, 0);

            test0.foreach([&](nlrd & item){
                xassert_eq(init_value, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, false);
            xassert_eq(test0->addition_bit, 0);
        }

        xassert_nlrd(0, 0, 0, 8192/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());


        // 测试构造函数 array_t(array_custom_free_invoke custom_free, args_t && ... list)
        used_bytes = inc::memory::used_bytes();
        {
            ary test0(xcstyle(inc::array_header_infop info, voidp mem){
                auto bytes = info->total_bytes_when_item_is<nlrd>();
                inc::memory::default_free<void>(mem, bytes);
            }, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

            xassert_nlrd(10/* test0 */, 0, 0, 0);

            test0.foreach([&](uxx index, nlrd & item){
                xassert_eq(index, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, true);
            xassert_eq(test0->addition_bit, 0);
        }

        xassert_nlrd(0, 0, 0, 10/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());


        // 测试构造函数 array_t(args_t && ... list)
        used_bytes = inc::memory::used_bytes();
        {
            ary test0{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            xassert_nlrd(10/* test0 */, 0, 0, 0);

            test0.foreach([&](uxx index, nlrd & item){
                xassert_eq(index + 1, item.value);
            });

            // 只要有 custom_free， 那么 is_requires_free 就一定是 true，其次如果没有使用外部分配内存，那么也是 true
            xassert_eq(test0->is_requires_free, true);
            xassert_eq(test0->is_requires_destruction, true);
            xassert_eq(test0->has_custom_free, false);
            xassert_eq(test0->addition_bit, 0);
        }

        xassert_nlrd(0, 0, 0, 10/* test0 */);
        xassert_eq(used_bytes, inc::memory::used_bytes());
    };
}

#endif
